/**
 *  @(#)  IFAAAuthenticator  module    1.0  2017/03/24
 *
 *  Copyright  (c)  2017,  IFAA  and/or  its  affiliates.  All  rights  reserved.
 *
 *  Redistribution  and  use  in  source  and  binary  forms,  with  or  without
 *  modification,  are  permitted  provided  that  the  following  conditions  are  met:
 *
 *  -Redistribution  of  source  code  must  retain  the  above  copyright  notice,  this
 *    list  of  conditions  and  the  following  disclaimer.
 *
 *  -Redistribution  in  binary  form  must  reproduce  the  above  copyright  notice,
 *    this  list  of  conditions  and  the  following  disclaimer  in  the  documentation
 *    and/or  other  materials  provided  with  the  distribution.
 *
 *  Neither  the  name  of  IFAA  or  the  names  of  contributors  may
 *  be  used  to  endorse  or  promote  products  derived  from  this  software  without
 *  specific  prior  written  permission.
 *
 *  This  software  is  provided  "AS  IS,"  without  a  warranty  of  any  kind.  ALL
 *  EXPRESS  OR  IMPLIED  CONDITIONS,  REPRESENTATIONS  AND  WARRANTIES,  INCLUDING
 *  ANY  IMPLIED  WARRANTY  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR  PURPOSE
 *  OR  NON-INFRINGEMENT,  ARE  HEREBY  EXCLUDED.  IFAA,  ORG.
 *  AND  ITS  LICENSORS  SHALL  NOT  BE  LIABLE  FOR  ANY  DAMAGES  SUFFERED  BY  LICENSEE
 *  AS  A  RESULT  OF  USING,  MODIFYING  OR  DISTRIBUTING  THIS  SOFTWARE  OR  ITS
 *  DERIVATIVES.  IN  NO  EVENT  WILL  IFAA  OR  ITS  LICENSORS  BE  LIABLE  FOR  ANY  LOST
 *  REVENUE,  PROFIT  OR  DATA,  OR  FOR  DIRECT,  INDIRECT,  SPECIAL,  CONSEQUENTIAL,
 *  INCIDENTAL  OR  PUNITIVE  DAMAGES,  HOWEVER  CAUSED  AND  REGARDLESS  OF  THE  THEORY
 *  OF  LIABILITY,  ARISING  OUT  OF  THE  USE  OF  OR  INABILITY  TO  USE  THIS  SOFTWARE,
 *  EVEN  IF  IFAA  HAS  BEEN  ADVISED  OF  THE  POSSIBILITY  OF  SUCH  DAMAGES.
 *
 *  You  acknowledge  that  this  software  is  not  designed,  licensed  or  intended
 *  for  use  in  the  design,  construction,  operation  or  maintenance  of  any
 *  nuclear  facility.
 *
 */
package com.ifaa.sdk.authenticatorservice.fingerprint.manager;

import org.ifaa.android.manager.IFAAManager;
import org.ifaa.android.manager.IFAAManagerV2;

import android.content.Context;
import android.util.Base64;

import com.ifaa.sdk.util.ByteUtils;
import com.ifaa.sdk.authenticatorservice.fingerprint.ta.TACommands;
import com.ifaa.sdk.authenticatorservice.fingerprint.ta.TAInterationV1;
import com.ifaa.sdk.authenticatorservice.message.Result;
import com.ifaa.sdk.auth.AuthenticatorLOG;
import com.ifaa.sdk.util.CommonUtils;

/**
 * 
 * @author qiyi.wxc
 * @version $Id: IFAAFingerprintManagerAdapter.java, v 0.1 2015年12月3日 下午2:20:57 qiyi.wxc Exp $
 */
public class IFAAFingerprintManagerAdapter {

    private static IFAAFingerprintManagerAdapter sInstance;
    private static final Object mInstanceLock = new Object();

    private Context mContext;

    private IFAAManager mIFAAManager;
    private IFAAFingerprintManagerFacade mFingerprintManagerFacade;

    private IFAAFingerprintManagerAdapter(Context context) {
        mContext = context;
        mIFAAManager = IFAAFingerprintManagerFactory.getIFAAManager(context);
        try {
            mFingerprintManagerFacade = IFAAFingerprintManagerCompat.getInstance(context);
        } catch (Throwable e) {
            // do nothing
        }
        if (mFingerprintManagerFacade == null) {
            try {
                mFingerprintManagerFacade = IFAAClientFingerprintManager.getInstance(context);
            } catch (Throwable e) {
                // do nothing
            }
        }
    }

    public static IFAAFingerprintManagerAdapter getInstance(Context context) {
        synchronized (mInstanceLock) {
            if (sInstance == null) {
                sInstance = new IFAAFingerprintManagerAdapter(context);
            }
            return sInstance;
        }
    }

    public void authenticate(IFAAFingerprintCallback callback) {
        if (mContext == null) {
            if (callback != null) {
                callback.onAuthenticationError(-1, "context is null");
            }
            return;
        }

        if (mFingerprintManagerFacade == null) {
            if (callback != null) {
                callback.onAuthenticationError(-1, "fingerprint service is null");
            }
            return;
        }

        if (!mFingerprintManagerFacade.isHardwareDetected()) {
            if (callback != null) {
                callback.onAuthenticationError(-1, "hardware is not support");
            }
            return;
        }

        try {
            mFingerprintManagerFacade.authenticate(callback);
        } catch (Exception e) {
            if (callback != null) {
                callback.onAuthenticationError(-1, "fingerprint authenticate error");
            }
        }
    }

    synchronized public byte[] invokeCmd(byte[] param) {
        if (mIFAAManager.getVersion() == 2) {
            try {
                return ((IFAAManagerV2) mIFAAManager).processCmdV2(mContext, param);
            } catch (Exception e) {
                AuthenticatorLOG.error(e);
                return null;
            }
        } else {
            return mIFAAManager.processCmd(mContext, param);
        }
    }

    synchronized public boolean startFingerprintManager() {
        try {
            long tmCost = System.currentTimeMillis();
            int res = mIFAAManager.startBIOManager(mContext, 1);
            tmCost = System.currentTimeMillis() - tmCost;
            return  res == 0;
        } catch (Throwable e) {
            AuthenticatorLOG.error(e);
            return false;
        }
    }

    synchronized public String getDeviceModel() {
        long tmCost = System.currentTimeMillis();
        String deviceModel = mIFAAManager.getDeviceModel();
        tmCost = System.currentTimeMillis() - tmCost;
        if (!CommonUtils.isBlank(deviceModel)) {
            deviceModel = deviceModel.replace(" ", "_");
        }
        return deviceModel;
    }

    public void cancel() {
        if (mFingerprintManagerFacade != null) {
            mFingerprintManagerFacade.cancel();
        }
    }

    public boolean isHardwareDetected() {
        if (mFingerprintManagerFacade != null) {
            return mFingerprintManagerFacade.isHardwareDetected();
        }
        return false;
    }

    public boolean hasEnrolledFingerprints() {
        if (mFingerprintManagerFacade != null) {
            return mFingerprintManagerFacade.hasEnrolledFingerprints();
        }
        return false;
    }

    /**
     * TA返回状态码定义：
     * 
     * 
     * @param userID
     * @return
     */
    public int getUserStatus(String userID) {
        if (CommonUtils.isBlank(userID)) {
            return -1;
        }

        try {
            long tmCost = System.currentTimeMillis();
            Result result = TAInterationV1.sendCommandAndData(mContext,
                TACommands.COMMAND_GET_USERSTATUS, userID.getBytes());
            tmCost = System.currentTimeMillis() - tmCost;
            switch (result.getStatus()) {
                case Result.IFAA_ERR_SUCCESS://0:
                    AuthenticatorLOG.fpInfo("ifaa original user status: "
                                            + ByteUtils.toInt(result.getData()));
                    return 2;
                case Result.IFAA_ERR_NOT_MATCH://0x7A00000F:
                    // 开通指纹被删掉
                    return 1;
                case Result.IFAA_ERR_READ://0x7A00000C:
                    // 未开通
                    return 0;
                default:
                    break;
            }
        } catch (Throwable e) {
            AuthenticatorLOG.error(e);
        }

        return -1;
    }

    public String getDeviceID() {
        try {
            long tmCost = System.currentTimeMillis();
            Result result = TAInterationV1.sendCommand(mContext, TACommands.COMMAND_GETDEVICEID);
            tmCost = System.currentTimeMillis() - tmCost;
            if (result.getStatus() == 0) {
                String deviceId = Base64.encodeToString(result.getData(), Base64.URL_SAFE);
                deviceId = deviceId.replace("\n", "");
                return deviceId;
            } else {
            }
        } catch (Throwable e) {
            AuthenticatorLOG.error(e);
        }
        return null;
    }

    public int getTaVersion() {
        try {
            long tmCost = System.currentTimeMillis();
            Result result = TAInterationV1.sendCommand(mContext, TACommands.COMMAND_GET_TA_VERSION);
            tmCost = System.currentTimeMillis() - tmCost;
            if (result.getStatus() == 0) {
                byte[] taversion = result.getData();
                return ByteUtils.toInt(taversion);
            } else {
            }
        } catch (Throwable e) {
            AuthenticatorLOG.error(e);
        }
        return -1;
    }
}
